//==============================================================================
//
//              DLexer - the lexer class in the objc-site
//
//               Copyright (C) 2003  Dick van Oudheusden
//  
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//==============================================================================
// 
//  $Date: 2003-07-19 17:51:06 $ $Revision: 1.1 $
//
//==============================================================================

#include "ofc/DLexer.h"

///
/// #include "ofc/config.h"
///
/// // The DLexer class implements a lexer. It supports comments, operators,
/// // keywords, identifiers, strings, characters and numbers. It supports
/// // including of other DataReadables. 
///
///
/// typedef struct
/// {
///   char      *word;
///   int        key;
/// }
/// DLexerKeyWord;
///
///
/// @interface DLexer : Object
/// {
/// @public
///   BOOL           _caseSensitive; // is the lexer case sensitive
///   DLexerReader   _current;       // the current reader
///   DList         *_readers;       // the stack with the readers
///   DLexerKeyWord *_keyWords;      // the keywords for the lexer
/// }
///

@implementation DLexer

//// Constructors

//
// Initialises to an empty lexer
//
// @return the object
//

- init 
{
  [super init];

  _readers = [DList alloc];
  
  _caseSensitive = YES;
  _keyWords      = NULL;
  _current       = nil;
      
  [_readers init];
  
  return self;
}

//
// Initialise a lexer
//
// @param caseSensitive   should the lexer be case sensitive 
// @param keyWords        the keywords for the lexer
//
// @return the object
//

- init :(BOOL) caseSensitive :(DLexerKeyWord *) keyWords
{
  [self init];

  _caseSensitive = caseSensitive;
  _keyWords      = keyWords;

  return self;
}

//// Deconstructor

//
// Free the object
//
// @return the object
//

- free
{
  [_readers free];
  
  [super free];

  return self;
}



//// Members

//
// Return the current reader name
//
// @return the current reader name (or NULL)
//

- (const char *) name
{
  return NULL;
}

//
// Return the current line number in the reader
//
// @return the current line number in the reader (or 0)
//

- (int) lineno
{
  return 0;
}

//
// Return if the lexer is case sensitive
//
// @return is the lexer case sensitive
//

- (BOOL) caseSensitive
{
  return _caseSensitive;
}




//// Main services

//
// Report an error on stderr
//
// @param message  the error message
//
// @return the object
//

- report :(const char *) message
{
  if (_current != nil)
  {
    fprintf(stderr, "%s, line %d: %s\n", _current._name, _current._line, message);
  }
  else
  {
    fprintf(stderr, "Unexpected error: %s\n", message);
  }
}

//
// Get a token from the current reader
//
// @return the token
//

- (int) getToken
{
  int token = DLEXER_UNKNOWN;

  while ((token == DLEXER_UNKNOWN) && (_current != nil))
  {
    if ([self isOperator])
    {
      token = DLEXER_OPERATOR;
    }
    else if ([self isIdentifier])
    {
      token = DLEXER_IDENTIFIER;
    }
    else if ([self isNumber])
    {
      token = DLEXER_NUMBER:
    }
    else if ([self isString])
    {
      token = DLEXER_STRING;
    }
    else if ([self isChar])
    {
      token = DLEXER_CHAR;
    }
    else if ([self isEOL])
    {
      // increment line
    }
    else if (![self isWhiteSpace])
    {
      [self report :"unexpected character"];
    }
  }

  return token;
}



//// Reader methods

//
// Start using a reader
//
// @param reader   the reader to read from (will be freed)
// @param name     the name for the reader 
//
// @return the object
//

- load :(DataReader *) reader :(const char *) name
{
  return self;
}

//
// Stop using the current reader
//
// @return the object
//

- unload
{
  return self;
}




//// Lexer methods

//
// Try to scan an end of line
//
// @return success
//

- (BOOL) isEOL
{
  return NO;
}

//
// Try to scan white space
//
// @return success
//

- (BOOL) isWhiteSpace
{
  return NO;
}

//
// Try to scan an operator
//
// @return success
//

- (BOOL) isOperator
{
  return NO;
}

//
// Try to scan a string
//
// @return success
//

- (BOOL) isString
{
  return NO;
}

//
// Try to scan a character
//
// @return success
//

- (BOOL) isChar
{
  return NO;
}

//
// Try to scan a number
//
// @return success
//

- (BOOL) isNumber
{
  return NO;
}

//
// Try to scan an identifier
//
// @return success
//

- (BOOL) isIdentifier
{
  return NO;
}

//
// Try to scan a comment
//
// @return success
//

- (BOOL) isComment
{
}




//// Tests

//
// Test the class
//

+ (void) test
{
  
  STARTTEST();

  TEST(YES);

  STOPTEST();
}

@end

/*==========================================================================*/
